
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vincenty大地测量计算器</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
    <style>
        :root {
            --primary-color: #667eea;
            --secondary-color: #764ba2;
            --success-color: #28a745;
            --warning-color: #ffc107;
        }
        
        body {
            background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
            min-height: 100vh;
            font-family: 'Microsoft YaHei', 'Segoe UI', sans-serif;
        }
        
        .navbar-brand {
            font-weight: bold;
            font-size: 1.5rem;
        }
        
        .calculator-card {
            background: rgba(255, 255, 255, 0.95);
            border-radius: 20px;
            box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1);
            backdrop-filter: blur(10px);
            border: 1px solid rgba(255, 255, 255, 0.2);
            margin-bottom: 2rem;
            transition: transform 0.3s ease;
        }
        
        .calculator-card:hover {
            transform: translateY(-5px);
        }
        
        .nav-tabs {
            border-bottom: 2px solid #e9ecef;
            margin-bottom: 1.5rem;
        }
        
        .nav-tabs .nav-link {
            border: none;
            color: #6c757d;
            font-weight: 500;
            padding: 12px 24px;
            border-radius: 10px 10px 0 0;
            transition: all 0.3s ease;
        }
        
        .nav-tabs .nav-link:hover {
            color: var(--primary-color);
            background-color: rgba(102, 126, 234, 0.1);
        }
        
        .nav-tabs .nav-link.active {
            background: linear-gradient(45deg, var(--primary-color), var(--secondary-color));
            color: white;
            border: none;
            box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
        }
        
        .form-control {
            border-radius: 12px;
            border: 2px solid #e9ecef;
            padding: 12px 15px;
            font-size: 1rem;
            transition: all 0.3s ease;
        }
        
        .form-control:focus {
            border-color: var(--primary-color);
            box-shadow: 0 0 0 0.25rem rgba(102, 126, 234, 0.25);
            transform: translateY(-2px);
        }
        
        .btn-primary {
            background: linear-gradient(45deg, var(--primary-color), var(--secondary-color));
            border: none;
            border-radius: 12px;
            padding: 12px 30px;
            font-weight: 600;
            font-size: 1.1rem;
            transition: all 0.3s ease;
            box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
        }
        
        .btn-primary:hover {
            transform: translateY(-3px);
            box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
        }
        
        .btn-outline-secondary {
            border-radius: 12px;
            padding: 12px 30px;
            font-weight: 600;
        }
        
        .result-box {
            background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
            border-radius: 15px;
            padding: 25px;
            margin-top: 25px;
            border-left: 5px solid var(--primary-color);
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
        }
        
        .coordinate-example {
            font-size: 0.85em;
            color: #6c757d;
            margin-top: 8px;
            font-style: italic;
        }
        
        .loading {
            display: none;
            text-align: center;
            padding: 30px;
        }
        
        .feature-icon {
            width: 60px;
            height: 60px;
            background: linear-gradient(45deg, var(--primary-color), var(--secondary-color));
            border-radius: 15px;
            display: flex;
            align-items: center;
            justify-content: center;
            margin: 0 auto 15px;
            color: white;
            font-size: 1.5rem;
        }
        
        .history-item {
            background: white;
            border-radius: 10px;
            padding: 15px;
            margin-bottom: 10px;
            border-left: 4px solid var(--success-color);
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
        }
        
        .input-group {
            border-radius: 12px;
            overflow: hidden;
        }
        
        .input-group-text {
            background: linear-gradient(45deg, var(--primary-color), var(--secondary-color));
            color: white;
            border: none;
            font-weight: 600;
        }
        
        @media (max-width: 768px) {
            .calculator-card {
                margin: 1rem;
                border-radius: 15px;
            }
            
            .nav-tabs .nav-link {
                padding: 10px 15px;
                font-size: 0.9rem;
            }
        }
        
        .feature-card {
            transition: transform 0.3s ease;
        }
        
        .feature-card:hover {
            transform: translateY(-5px);
        }
    </style>
</head>
<body>
    <!-- 导航栏 -->
    <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
        <div class="container">
            <a class="navbar-brand" href="#">
                <i class="fas fa-calculator me-2"></i>
                Vincenty计算器
            </a>
            <div class="navbar-text">
                <small>专业大地测量工具</small>
            </div>
        </div>
    </nav>

    <div class="container mt-4">
        <div class="row justify-content-center">
            <div class="col-lg-10">
                <!-- 主计算器卡片 -->
                <div class="calculator-card">
                    <div class="card-body p-4">
                        <!-- 选项卡 -->
                        <ul class="nav nav-tabs nav-justified mb-4" id="calcTabs" role="tablist">
                            <li class="nav-item" role="presentation">
                                <button class="nav-link active" id="inverse-tab" data-bs-toggle="tab" data-bs-target="#inverse" type="button" role="tab">
                                    <i class="fas fa-ruler-combined me-2"></i>坐标求距离
                                </button>
                            </li>
                            <li class="nav-item" role="presentation">
                                <button class="nav-link" id="direct-tab" data-bs-toggle="tab" data-bs-target="#direct" type="button" role="tab">
                                    <i class="fas fa-location-arrow me-2"></i>距离求坐标
                                </button>
                            </li>
                            <li class="nav-item" role="presentation">
                                <button class="nav-link" id="convert-tab" data-bs-toggle="tab" data-bs-target="#convert" type="button" role="tab">
                                    <i class="fas fa-exchange-alt me-2"></i>坐标转换
                                </button>
                            </li>
                        </ul>

                        <div class="tab-content" id="calcTabsContent">
                            <!-- 反算选项卡 -->
                            <div class="tab-pane fade show active" id="inverse" role="tabpanel">
                                <div class="row">
                                    <div class="col-md-6">
                                        <h5 class="mb-3"><i class="fas fa-map-marker-alt me-2"></i>第一点坐标</h5>
                                        <div class="mb-3">
                                            <label class="form-label fw-bold">纬度</label>
                                            <div class="input-group">
                                                <span class="input-group-text"><i class="fas fa-latitude"></i></span>
                                                <input type="text" class="form-control" id="lat1" placeholder="例如: 39.9042 或 39°54'15.12&quot;N">
                                            </div>
                                            <div class="coordinate-example">支持格式: 39.9042 或 39°54'15.12"N 或 39 54 15.12 N</div>
                                        </div>
                                        <div class="mb-3">
                                            <label class="form-label fw-bold">经度</label>
                                            <div class="input-group">
                                                <span class="input-group-text"><i class="fas fa-longitude"></i></span>
                                                <input type="text" class="form-control" id="lon1" placeholder="例如: 116.4074 或 116°24'26.64&quot;E">
                                            </div>
                                            <div class="coordinate-example">支持格式: 116.4074 或 116°24'26.64"E 或 116 24 26.64 E</div>
                                        </div>
                                    </div>
                                    <div class="col-md-6">
                                        <h5 class="mb-3"><i class="fas fa-map-marker-alt me-2"></i>第二点坐标</h5>
                                        <div class="mb-3">
                                            <label class="form-label fw-bold">纬度</label>
                                            <div class="input-group">
                                                <span class="input-group-text"><i class="fas fa-latitude"></i></span>
                                                <input type="text" class="form-control" id="lat2" placeholder="例如: 31.2304 或 31°13'49.44&quot;N">
                                            </div>
                                        </div>
                                        <div class="mb-3">
                                            <label class="form-label fw-bold">经度</label>
                                            <div class="input-group">
                                                <span class="input-group-text"><i class="fas fa-longitude"></i></span>
                                                <input type="text" class="form-control" id="lon2" placeholder="例如: 121.4737 或 121°28'25.32&quot;E">
                                            </div>
                                        </div>
                                    </div>
                                </div>
                                <div class="text-center mt-4">
                                    <button class="btn btn-primary me-3" onclick="calculateInverse()">
                                        <i class="fas fa-calculator me-2"></i>计算距离和方位角
                                    </button>
                                    <button class="btn btn-outline-secondary" onclick="clearInverse()">
                                        <i class="fas fa-eraser me-2"></i>清空
                                    </button>
                                </div>
                                <div class="loading" id="inverseLoading">
                                    <div class="spinner-border text-primary" role="status">
                                        <span class="visually-hidden">计算中...</span>
                                    </div>
                                    <p class="mt-2 fw-bold">计算中，请稍候...</p>
                                </div>
                                <div class="result-box" id="inverseResult" style="display: none;">
                                    <h5 class="mb-3"><i class="fas fa-chart-line me-2"></i>计算结果</h5>
                                    <div id="inverseResultContent"></div>
                                </div>
                            </div>

                            <!-- 正算选项卡 -->
                            <div class="tab-pane fade" id="direct" role="tabpanel">
                                <div class="row">
                                    <div class="col-md-6">
                                        <h5 class="mb-3"><i class="fas fa-play-circle me-2"></i>起点坐标</h5>
                                        <div class="mb-3">
                                            <label class="form-label fw-bold">纬度</label>
                                            <div class="input-group">
                                                <span class="input-group-text"><i class="fas fa-latitude"></i></span>
                                                <input type="text" class="form-control" id="startLat" placeholder="例如: 39.9042">
                                            </div>
                                        </div>
                                        <div class="mb-3">
                                            <label class="form-label fw-bold">经度</label>
                                            <div class="input-group">
                                                <span class="input-group-text"><i class="fas fa-longitude"></i></span>
                                                <input type="text" class="form-control" id="startLon" placeholder="例如: 116.4074">
                                            </div>
                                        </div>
                                    </div>
                                    <div class="col-md-6">
                                        <h5 class="mb-3"><i class="fas fa-cogs me-2"></i>计算参数</h5>
                                        <div class="mb-3">
                                            <label class="form-label fw-bold">方位角 (度)</label>
                                            <div class="input-group">
                                                <span class="input-group-text"><i class="fas fa-compass"></i></span>
                                                <input type="number" class="form-control" id="azimuth" placeholder="0-360度" min="0" max="360" step="0.001">
                                            </div>
                                        </div>
                                        <div class="mb-3">
                                            <label class="form-label fw-bold">距离 (米)</label>
                                            <div class="input-group">
                                                <span class="input-group-text"><i class="fas fa-ruler"></i></span>
                                                <input type="number" class="form-control" id="distance" placeholder="大于0" min="0.001" step="0.001">
                                            </div>
                                        </div>
                                    </div>
                                </div>
                                <div class="text-center mt-4">
                                    <button class="btn btn-primary me-3" onclick="calculateDirect()">
                                        <i class="fas fa-calculator me-2"></i>计算终点坐标
                                    </button>
                                    <button class="btn btn-outline-secondary" onclick="clearDirect()">
                                        <i class="fas fa-eraser me-2"></i>清空
                                    </button>
                                </div>
                                <div class="loading" id="directLoading">
                                    <div class="spinner-border text-primary" role="status">
                                        <span class="visually-hidden">计算中...</span>
                                    </div>
                                    <p class="mt-2 fw-bold">计算中，请稍候...</p>
                                </div>
                                <div class="result-box" id="directResult" style="display: none;">
                                    <h5 class="mb-3"><i class="fas fa-chart-line me-2"></i>计算结果</h5>
                                    <div id="directResultContent"></div>
                                </div>
                            </div>

                            <!-- 坐标转换选项卡 -->
                            <div class="tab-pane fade" id="convert" role="tabpanel">
                                <div class="row">
                                    <div class="col-12">
                                        <h5 class="mb-3"><i class="fas fa-sync-alt me-2"></i>坐标格式转换</h5>
                                        <div class="mb-3">
                                            <label class="form-label fw-bold">输入坐标</label>
                                            <div class="input-group">
                                                <span class="input-group-text"><i class="fas fa-map-marker-alt"></i></span>
                                                <input type="text" class="form-control" id="convertInput" placeholder="支持十进制度或度分秒格式">
                                            </div>
                                            <div class="coordinate-example">
                                                示例: 39.9042 或 39°54'15.12"N 或 39 54 15.12 N
                                            </div>
                                        </div>
                                    </div>
                                </div>
                                <div class="text-center mt-4">
                                    <button class="btn btn-primary me-3" onclick="convertCoordinate()">
                                        <i class="fas fa-exchange-alt me-2"></i>转换格式
                                    </button>
                                    <button class="btn btn-outline-secondary" onclick="clearConvert()">
                                        <i class="fas fa-eraser me-2"></i>清空
                                    </button>
                                </div>
                                <div class="loading" id="convertLoading">
                                    <div class="spinner-border text-primary" role="status">
                                        <span class="visually-hidden">转换中...</span>
                                    </div>
                                    <p class="mt-2 fw-bold">转换中，请稍候...</p>
                                </div>
                                <div class="result-box" id="convertResult" style="display: none;">
                                    <h5 class="mb-3"><i class="fas fa-chart-line me-2"></i>转换结果</h5>
                                    <div id="convertResultContent"></div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>

                <!-- 功能特性介绍 -->
                <div class="row">
                    <div class="col-md-4 mb-3">
                        <div class="calculator-card feature-card h-100">
                            <div class="card-body text-center">
                                <div class="feature-icon">
                                    <i class="fas fa-ruler-combined"></i>
                                </div>
                                <h5>精确计算</h5>
                                <p class="text-muted">基于Vincenty算法，提供毫米级精度的距离计算</p>
                            </div>
                        </div>
                    </div>
                    <div class="col-md-4 mb-3">
                        <div class="calculator-card feature-card h-100">
                            <div class="card-body text-center">
                                <div class="feature-icon">
                                    <i class="fas fa-exchange-alt"></i>
                                </div>
                                <h5>多种格式</h5>
                                <p class="text-muted">支持十进制度和度分秒坐标格式的相互转换</p>
                            </div>
                        </div>
                    </div>
                    <div class="col-md-4 mb-3">
                        <div class="calculator-card feature-card h-100">
                            <div class="card-body text-center">
                                <div class="feature-icon">
                                    <i class="fas fa-mobile-alt"></i>
                                </div>
                                <h5>响应式设计</h5>
                                <p class="text-muted">完美适配手机、平板和电脑等各种设备</p>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <footer class="bg-dark text-white text-center py-4 mt-5">
        <div class="container">
            <p class="mb-0">Vincenty大地测量计算器 &copy; 2024 - 专业测绘工具</p>
        </div>
    </footer>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
    <script>
        // Vincenty算法JavaScript实现
        class VincentyCalculator {
            static a = 6378137.0;
            static f = 1 / 298.257223563;
            static b = (1 - this.f) * this.a;
            
            static inverse(lat1, lon1, lat2, lon2, maxIterations = 200, tolerance = 1e-12) {
                const toRad = deg => deg * Math.PI / 180;
                const toDeg = rad => rad * 180 / Math.PI;
                
                let lat1Rad = toRad(lat1);
                let lon1Rad = toRad(lon1);
                let lat2Rad = toRad(lat2);
                let lon2Rad = toRad(lon2);
                
                let L = lon2Rad - lon1Rad;
                let U1 = Math.atan((1 - this.f) * Math.tan(lat1Rad));
                let U2 = Math.atan((1 - this.f) * Math.tan(lat2Rad));
                let sinU1 = Math.sin(U1);
                let cosU1 = Math.cos(U1);
                let sinU2 = Math.sin(U2);
                let cosU2 = Math.cos(U2);
                
                let lambda = L;
                let lambdaPrev = 2 * Math.PI;
                let iterationCount = 0;
                
                let sinLambda, cosLambda, sinSigma, cosSigma, sigma, sinAlpha, cosSqAlpha, cos2SigmaM;
                
                while (iterationCount < maxIterations && Math.abs(lambda - lambdaPrev) > tolerance) {
                    sinLambda = Math.sin(lambda);
                    cosLambda = Math.cos(lambda);
                    sinSigma = Math.sqrt((cosU2 * sinLambda) ** 2 + 
                                       (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda) ** 2);
                    
                    if (sinSigma === 0) {
                        return { distance: 0, forwardAzimuth: 0, reverseAzimuth: 0 };
                    }
                    
                    cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda;
                    sigma = Math.atan2(sinSigma, cosSigma);
                    sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
                    cosSqAlpha = 1 - sinAlpha * sinAlpha;
                    
                    cos2SigmaM = cosSqAlpha === 0 ? 0 : cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha;
                    
                    let C = this.f / 16 * cosSqAlpha * (4 + this.f * (4 - 3 * cosSqAlpha));
                    lambdaPrev = lambda;
                    lambda = L + (1 - C) * this.f * sinAlpha * 
                            (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)));
                    
                    iterationCount++;
                }
                
                if (iterationCount === maxIterations) {
                    throw new Error("Vincenty算法未收敛");
                }
                
                let uSq = cosSqAlpha * (this.a ** 2 - this.b ** 2) / (this.b ** 2);
                let A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
                let B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
                
                let deltaSigma = B * sinSigma * (
                    cos2SigmaM + B / 4 * (
                        cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) - 
                        B / 6 * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM)
                    )
                );
                
                let s = this.b * A * (sigma - deltaSigma);
                
                let alpha1 = Math.atan2(cosU2 * sinLambda, cosU1 * sinU2 - sinU1 * cosU2 * cosLambda);
                let alpha2 = Math.atan2(cosU1 * sinLambda, -sinU1 * cosU2 + cosU1 * sinU2 * cosLambda);
                
                alpha1 = toDeg(alpha1) % 360;
                alpha2 = toDeg(alpha2) % 360;
                
                return {
                    distance: s,
                    forwardAzimuth: alpha1,
                    reverseAzimuth: alpha2
                };
            }
            
            static direct(lat1, lon1, alpha1, s, maxIterations = 200, tolerance = 1e-12) {
                const toRad = deg => deg * Math.PI / 180;
                const toDeg = rad => rad * 180 / Math.PI;
                
                let lat1Rad = toRad(lat1);
                let lon1Rad = toRad(lon1);
                let alpha1Rad = toRad(alpha1);
                
                let tanU1 = (1 - this.f) * Math.tan(lat1Rad);
                let cosU1 = 1 / Math.sqrt(1 + tanU1 * tanU1);
                let sinU1 = tanU1 * cosU1;
                
                let sigma1 = Math.atan2(tanU1, Math.cos(alpha1Rad));
                let sinAlpha = cosU1 * Math.sin(alpha1Rad);
                let cosSqAlpha = 1 - sinAlpha * sinAlpha;
                
                let uSq = cosSqAlpha * (this.a ** 2 - this.b ** 2) / (this.b ** 2);
                let A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
                let B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
                
                let sigma = s / (this.b * A);
                let sigmaPrev = 2 * Math.PI;
                let iterationCount = 0;
                
                while (iterationCount < maxIterations && Math.abs(sigma - sigmaPrev) > tolerance) {
                    sigmaPrev = sigma;
                    let cos2SigmaM = Math.cos(2 * sigma1 + sigma);
                    let sinSigma = Math.sin(sigma);
                    let cosSigma = Math.cos(sigma);
                    
                    let deltaSigma = B * sinSigma * (
                        cos2SigmaM + B / 4 * (
                            cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) - 
                            B / 6 * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM)
                        )
                    );
                    
                    sigma = s / (this.b * A) + deltaSigma;
                    iterationCount++;
                }
                
                if (iterationCount === maxIterations) {
                    throw new Error("Vincenty正算算法未收敛");
                }
                
                let cos2SigmaM = Math.cos(2 * sigma1 + sigma);
                let sinSigma = Math.sin(sigma);
                let cosSigma = Math.cos(sigma);
                
                let lat2Rad = Math.atan2(
                    sinU1 * cosSigma + cosU1 * sinSigma * Math.cos(alpha1Rad),
                    (1 - this.f) * Math.sqrt(sinAlpha * sinAlpha + 
                                           (sinU1 * sinSigma - cosU1 * cosSigma * Math.cos(alpha1Rad)) ** 2)
                );
                
                let lambda = Math.atan2(
                    sinSigma * Math.sin(alpha1Rad),
                    cosU1 * cosSigma - sinU1 * sinSigma * Math.cos(alpha1Rad)
                );
                
                let C = this.f / 16 * cosSqAlpha * (4 + this.f * (4 - 3 * cosSqAlpha));
                let L = lambda - (1 - C) * this.f * sinAlpha * (
                    sigma + C * sinSigma * (
                        cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)
                    )
                );
                
                let lon2Rad = lon1Rad + L;
                
                let alpha2 = Math.atan2(
                    sinAlpha,
                    -sinU1 * sinSigma + cosU1 * cosSigma * Math.cos(alpha1Rad)
                );
                
                let lat2 = toDeg(lat2Rad);
                let lon2 = toDeg(lon2Rad);
                alpha2 = toDeg(alpha2) % 360;
                
                return {
                    endLat: lat2,
                    endLon: lon2,
                    reverseAzimuth: alpha2
                };
            }
        }

        // 坐标转换工具类
        class CoordinateConverter {
            static dmsToDd(dmsStr) {
                let str = dmsStr.trim()
                    .replace(/[°′″'"]/g, ' ')
                    .replace(/:/g, ' ')
                    .replace(/\s+/g, ' ')
                    .toUpperCase();
                
                const directions = { 'N': 1, 'S': -1, 'E': 1, 'W': -1 };
                let direction = 1;
                
                for (let dirChar in directions) {
                    if (str.includes(dirChar)) {
                        direction = directions[dirChar];
                        str = str.replace(dirChar, '').trim();
                        break;
                    }
                }
                
                if (str.startsWith('-')) {
                    direction = -1;
                    str = str.substring(1).trim();
                }
                
                let parts = str.split(' ');
                if (parts.length === 0) {
                    throw new Error("无效的度分秒格式");
                }
                
                let degrees, minutes = 0, seconds = 0;
                
                try {
                    degrees = parseFloat(parts[0]);
                } catch {
                    throw new Error("无效的度数值");
                }
                
                if (parts.length >= 2) {
                    try {
                        minutes = parseFloat(parts[1]);
                    } catch {
                        throw new Error("无效的分数值");
                    }
                }
                
                if (parts.length >= 3) {
                    try {
                        seconds = parseFloat(parts[2]);
                    } catch {
                        throw new Error("无效的秒数值");
                    }
                }
                
                let dd = degrees + minutes / 60.0 + seconds / 3600.0;
                return dd * direction;
            }
            
            static ddToDms(dd, coordType = 'lat') {
                const direction = coordType === 'lat' 
                    ? (dd >= 0 ? 'N' : 'S')
                    : (dd >= 0 ? 'E' : 'W');
                
                const ddAbs = Math.abs(dd);
                const degrees = Math.floor(ddAbs);
                const minutesFull = (ddAbs - degrees) * 60;
                const minutes = Math.floor(minutesFull);
                const seconds = (minutesFull - minutes) * 60;
                
                const secondsStr = seconds < 10 ? `0${seconds.toFixed(4)}` : seconds.toFixed(4);
                return `${degrees}°${minutes}'${secondsStr}"${direction}`;
            }
            
            static parseCoordinate(inputStr, coordType = 'auto') {
                inputStr = inputStr.trim();
                
                if (!inputStr) {
                    throw new Error("坐标不能为空");
                }
                
                // 尝试解析为十进制度
                try {
                    let dd = parseFloat(inputStr);
                    if (isNaN(dd)) throw new Error("不是有效的数字");
                    
                    if (coordType === 'lat' && (dd < -90 || dd > 90)) {
                        throw new Error("纬度必须在-90到90度之间");
                    } else if (coordType === 'lon' && (dd < -180 || dd > 180)) {
                        throw new Error("经度必须在-180到180度之间");
                    }
                    return dd;
                } catch {
                    // 不是十进制度，尝试解析为度分秒
                }
                
                try {
                    let dd = this.dmsToDd(inputStr);
                    if (coordType === 'lat' && (dd < -90 || dd > 90)) {
                        throw new Error("纬度必须在-90到90度之间");
                    } else if (coordType === 'lon' && (dd < -180 || dd > 180)) {
                        throw new Error("经度必须在-180到180度之间");
                    }
                    return dd;
                } catch (e) {
                    throw new Error(`无法解析坐标格式: ${inputStr} - ${e.message}`);
                }
            }
        }

        // 工具函数
        function showLoading(elementId) {
            document.getElementById(elementId).style.display = 'block';
        }

        function hideLoading(elementId) {
            document.getElementById(elementId).style.display = 'none';
        }

        function showResult(elementId) {
            document.getElementById(elementId).style.display = 'block';
        }

        function hideResult(elementId) {
            document.getElementById(elementId).style.display = 'none';
        }

        function showError(message) {
            alert('错误: ' + message);
        }

        // 反算计算
        function calculateInverse() {
            try {
                const lat1 = document.getElementById('lat1').value;
                const lon1 = document.getElementById('lon1').value;
                const lat2 = document.getElementById('lat2').value;
                const lon2 = document.getElementById('lon2').value;

                if (!lat1 || !lon1 || !lat2 || !lon2) {
                    showError('请填写所有坐标字段');
                    return;
                }

                showLoading('inverseLoading');
                hideResult('inverseResult');

                // 使用setTimeout让UI有机会更新
                setTimeout(() => {
                    try {
                        const lat1dd = CoordinateConverter.parseCoordinate(lat1, 'lat');
                        const lon1dd = CoordinateConverter.parseCoordinate(lon1, 'lon');
                        const lat2dd = CoordinateConverter.parseCoordinate(lat2, 'lat');
                        const lon2dd = CoordinateConverter.parseCoordinate(lon2, 'lon');

                        const result = VincentyCalculator.inverse(lat1dd, lon1dd, lat2dd, lon2dd);

                        displayInverseResult(result, lat1dd, lon1dd, lat2dd, lon2dd);
                    } catch (error) {
                        showError(error.message);
                    } finally {
                        hideLoading('inverseLoading');
                    }
                }, 50);
            } catch (error) {
                hideLoading('inverseLoading');
                showError(error.message);
            }
        }

        // 正算计算
        function calculateDirect() {
            try {
                const startLat = document.getElementById('startLat').value;
                const startLon = document.getElementById('startLon').value;
                const azimuth = document.getElementById('azimuth').value;
                const distance = document.getElementById('distance').value;

                if (!startLat || !startLon || !azimuth || !distance) {
                    showError('请填写所有字段');
                    return;
                }

                const azimuthNum = parseFloat(azimuth);
                const distanceNum = parseFloat(distance);

                if (isNaN(azimuthNum) || azimuthNum < 0 || azimuthNum >= 360) {
                    showError('方位角必须在0-360度之间');
                    return;
                }

                if (isNaN(distanceNum) || distanceNum <= 0) {
                    showError('距离必须大于0');
                    return;
                }

                showLoading('directLoading');
                hideResult('directResult');

                setTimeout(() => {
                    try {
                        const startLatdd = CoordinateConverter.parseCoordinate(startLat, 'lat');
                        const startLondd = CoordinateConverter.parseCoordinate(startLon, 'lon');

                        const result = VincentyCalculator.direct(startLatdd, startLondd, azimuthNum, distanceNum);

                        displayDirectResult(result, startLatdd, startLondd, azimuthNum, distanceNum);
                    } catch (error) {
                        showError(error.message);
                    } finally {
                        hideLoading('directLoading');
                    }
                }, 50);
            } catch (error) {
                hideLoading('directLoading');
                showError(error.message);
            }
        }

        // 坐标转换
        function convertCoordinate() {
            try {
                const inputStr = document.getElementById('convertInput').value;

                if (!inputStr) {
                    showError('请输入要转换的坐标');
                    return;
                }

                showLoading('convertLoading');
                hideResult('convertResult');

                setTimeout(() => {
                    try {
                        const dd = CoordinateConverter.parseCoordinate(inputStr, 'auto');
                        const coordType = Math.abs(dd) <= 90 ? '纬度' : '经度';
                        const dms = CoordinateConverter.ddToDms(dd, Math.abs(dd) <= 90 ? 'lat' : 'lon');

                        displayConvertResult(inputStr, dd, dms, coordType);
                    } catch (error) {
                        showError(error.message);
                    } finally {
                        hideLoading('convertLoading');
                    }
                }, 50);
            } catch (error) {
                hideLoading('convertLoading');
                showError(error.message);
            }
        }

        // 显示反算结果
        function displayInverseResult(result, lat1, lon1, lat2, lon2) {
            const now = new Date();
            const timestamp = now.toLocaleString('zh-CN');
            
            const content = `
                <div class="mb-3">
                    <strong>起点坐标:</strong><br>
                    <span class="text-muted">十进制度:</span> (${lat1.toFixed(6)}°, ${lon1.toFixed(6)}°)<br>
                    <span class="text-muted">度分秒:</span> ${CoordinateConverter.ddToDms(lat1, 'lat')}, ${CoordinateConverter.ddToDms(lon1, 'lon')}
                </div>
                
                <div class="mb-3">
                    <strong>终点坐标:</strong><br>
                    <span class="text-muted">十进制度:</span> (${lat2.toFixed(6)}°, ${lon2.toFixed(6)}°)<br>
                    <span class="text-muted">度分秒:</span> ${CoordinateConverter.ddToDms(lat2, 'lat')}, ${CoordinateConverter.ddToDms(lon2, 'lon')}
                </div>
                
                <div class="mb-3">
                    <strong>计算结果:</strong><br>
                    <span class="text-success fw-bold">距离: ${result.distance.toFixed(3)} 米 (${(result.distance/1000).toFixed(6)} 公里)</span><br>
                    <span class="text-primary">正方位角: ${result.forwardAzimuth.toFixed(6)}°</span><br>
                    <span class="text-info">反方位角: ${result.reverseAzimuth.toFixed(6)}°</span>
                </div>
                
                <div class="text-muted small">
                    <i class="fas fa-clock me-1"></i>计算时间: ${timestamp}
                </div>
            `;
            document.getElementById('inverseResultContent').innerHTML = content;
            showResult('inverseResult');
        }

        // 显示正算结果
        function displayDirectResult(result, startLat, startLon, azimuth, distance) {
            const now = new Date();
            const timestamp = now.toLocaleString('zh-CN');
            
            const content = `
                <div class="mb-3">
                    <strong>起点坐标:</strong><br>
                    <span class="text-muted">度分秒:</span> ${CoordinateConverter.ddToDms(startLat, 'lat')}, ${CoordinateConverter.ddToDms(startLon, 'lon')}
                </div>
                
                <div class="mb-3">
                    <strong>计算参数:</strong><br>
                    <span class="text-muted">方位角:</span> ${azimuth.toFixed(6)}°<br>
                    <span class="text-muted">距离:</span> ${distance.toFixed(3)} 米
                </div>
                
                <div class="mb-3">
                    <strong>终点坐标:</strong><br>
                    <span class="text-success fw-bold">十进制度: (${result.endLat.toFixed(6)}°, ${result.endLon.toFixed(6)}°)</span><br>
                    <span class="text-muted">度分秒:</span> ${CoordinateConverter.ddToDms(result.endLat, 'lat')}, ${CoordinateConverter.ddToDms(result.endLon, 'lon')}
                </div>
                
                <div class="mb-3">
                    <span class="text-primary">反方位角: ${result.reverseAzimuth.toFixed(6)}°</span>
                </div>
                
                <div class="text-muted small">
                    <i class="fas fa-clock me-1"></i>计算时间: ${timestamp}
                </div>
            `;
            document.getElementById('directResultContent').innerHTML = content;
            showResult('directResult');
        }

        // 显示转换结果
        function displayConvertResult(inputStr, dd, dms, coordType) {
            const now = new Date();
            const timestamp = now.toLocaleString('zh-CN');
            
            const content = `
                <div class="mb-3">
                    <strong>输入坐标:</strong> ${inputStr}
                </div>
                
                <div class="mb-3">
                    <strong>十进制度:</strong><br>
                    <span class="text-success fw-bold">${dd.toFixed(8)}°</span>
                </div>
                
                <div class="mb-3">
                    <strong>度分秒:</strong><br>
                    <span class="text-primary">${dms}</span>
                </div>
                
                <div class="mb-3">
                    <strong>坐标类型:</strong> ${coordType}
                </div>
                
                <div class="text-muted small">
                    <i class="fas fa-clock me-1"></i>转换时间: ${timestamp}
                </div>
            `;
            document.getElementById('convertResultContent').innerHTML = content;
            showResult('convertResult');
        }

        // 清空函数
        function clearInverse() {
            document.getElementById('lat1').value = '';
            document.getElementById('lon1').value = '';
            document.getElementById('lat2').value = '';
            document.getElementById('lon2').value = '';
            hideResult('inverseResult');
        }

        function clearDirect() {
            document.getElementById('startLat').value = '';
            document.getElementById('startLon').value = '';
            document.getElementById('azimuth').value = '';
            document.getElementById('distance').value = '';
            hideResult('directResult');
        }

        function clearConvert() {
            document.getElementById('convertInput').value = '';
            hideResult('convertResult');
        }

        // 示例数据填充（可选）
        function fillExampleData() {
            document.getElementById('lat1').value = '39.9042';
            document.getElementById('lon1').value = '116.4074';
            document.getElementById('lat2').value = '31.2304';
            document.getElementById('lon2').value = '121.4737';
        }

        // 页面加载完成后执行
        document.addEventListener('DOMContentLoaded', function() {
            // 可以在这里添加页面加载后的初始化代码
            console.log('Vincenty计算器已加载');
        });
    </script>
</body>
</html>
